Skip to content

feat(workspaces): add workspace logo upload#4136

Merged
waleedlatif1 merged 11 commits intostagingfrom
waleedlatif1/workspace-logo-upload
Apr 13, 2026
Merged

feat(workspaces): add workspace logo upload#4136
waleedlatif1 merged 11 commits intostagingfrom
waleedlatif1/workspace-logo-upload

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Add workspace logo upload via right-click context menu on workspace items
  • New dedicated storage bucket for workspace logos with S3 and Azure support
  • Show uploaded logo in place of the default color + letter avatar across the sidebar
  • Route whitelabeling logo and wordmark uploads to the new storage bucket
  • Consolidate duplicate Workspace type definitions to use a single shared interface

Type of Change

  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 13, 2026 10:38pm

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 13, 2026

PR Summary

Medium Risk
Adds a new public file context and upload path gated by workspace admin checks, plus a DB schema change for workspace.logoUrl; mistakes could expose or break logo/file access across workspaces.

Overview
Enables workspace logos to be uploaded and shown in the sidebar workspace switcher/context menu, falling back to the existing color+initial avatar when no logo is set.

Introduces a new uploads context workspace-logos with S3/Azure config/env support and treats it as publicly servable (like profile-pictures/og-images), while restricting uploads to workspace admins and emitting audit + PostHog event workspace_logo_uploaded.

Extends the workspace API and client types/mutations to persist logoUrl (DB migration adds workspace.logo_url), and routes whitelabeling logo/wordmark uploads through the same workspace-logos storage context; also consolidates duplicate Workspace typings and expands image uploads to accept WebP.

Reviewed by Cursor Bugbot for commit 473785c. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 13, 2026

Greptile Summary

This PR adds workspace logo upload support via a right-click context menu, introduces a dedicated workspace-logos storage bucket (S3 + Azure), wires logos into the sidebar header, and consolidates the Workspace type. It also routes whitelabeling logo/wordmark uploads to the new bucket and adds a logo_url column to the workspace table.

The previous thread concerns — storage cleanup parity with profile-pictures and URL validation — have been acknowledged/addressed. All remaining findings are P2.

Confidence Score: 5/5

Safe to merge — all findings are P2 style/edge-case concerns with no blocking bugs or security issues

Server-side authorization is correct (admin-only upload + PATCH, URL validation, public serve for logos). The DB migration is additive and backwards-compatible. Prior review concerns (storage cleanup parity, arbitrary URL injection) have been acknowledged or addressed. The two remaining findings are code duplication and an edge-case workspaceIdRef drift that only affects audit logs in an unlikely navigation sequence, neither of which blocks shipping.

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-workspace-logo-upload.ts — code duplication and workspaceIdRef drift

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-workspace-logo-upload.ts New hook for workspace logo upload; near-duplicate of useProfilePictureUpload with the only addition being setTargetWorkspaceId; also contains a workspaceIdRef drift edge case
apps/sim/app/api/files/upload/route.ts Correctly adds workspace-logos context with admin-only authorization check, audit logging, and PostHog event capture
apps/sim/app/api/workspaces/[id]/route.ts PATCH route correctly validates logoUrl (must start with / or https://), requires admin permission, and records audit log for logo changes
apps/sim/app/api/files/authorization.ts workspace-logos correctly added to public-access contexts alongside profile-pictures and og-images; serve route also short-circuits auth for the new prefix
apps/sim/lib/uploads/config.ts S3_WORKSPACE_LOGOS_CONFIG and BLOB_WORKSPACE_LOGOS_CONFIG added correctly; switch cases handle workspace-logos with correct fallback to general config
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx useWorkspaceLogoUpload correctly wired; admin-only handlers passed down; logoTargetWorkspaceIdRef tracks target workspace for multi-workspace upload scenario
packages/db/migrations/0190_shocking_karma.sql Simple nullable text column addition to workspace table; backwards-compatible, no data migration needed
apps/sim/hooks/queries/workspace.ts Workspace type consolidated with logoUrl field; useUpdateWorkspace params extended with logoUrl; clean single source of truth

Sequence Diagram

sequenceDiagram
    actor User
    participant Sidebar
    participant Hook as useWorkspaceLogoUpload
    participant UploadAPI as POST /api/files/upload
    participant Storage as workspace-logos bucket
    participant PatchAPI as PATCH /api/workspaces/[id]
    participant DB as workspace.logo_url

    User->>Sidebar: Right-click workspace → Upload logo
    Sidebar->>Hook: setTargetWorkspaceId(workspaceId)
    Sidebar->>Sidebar: logoTargetWorkspaceIdRef = workspaceId
    Sidebar->>User: Open file picker

    User->>Sidebar: Select image file
    Sidebar->>Hook: handleFileChange(file)
    Hook->>Hook: validateFile (size ≤5MB, allowed type)
    Hook->>Hook: setPreviewUrl(objectURL)

    Hook->>UploadAPI: POST multipart (file, context=workspace-logos, workspaceId)
    UploadAPI->>UploadAPI: Verify user is workspace admin
    UploadAPI->>Storage: uploadFile(workspace-logos/ts-filename)
    Storage-->>UploadAPI: fileInfo.path
    UploadAPI->>UploadAPI: recordAudit + captureServerEvent
    UploadAPI-->>Hook: fileInfo.path

    Hook->>Hook: setPreviewUrl(serverUrl)
    Hook->>Sidebar: onUpload(serverUrl)
    Sidebar->>PatchAPI: PATCH { logoUrl: serverUrl }
    PatchAPI->>PatchAPI: Verify user is workspace admin
    PatchAPI->>PatchAPI: Validate logoUrl (starts with / or https://)
    PatchAPI->>DB: UPDATE workspace SET logo_url = serverUrl
    PatchAPI->>PatchAPI: recordAudit
    PatchAPI-->>Sidebar: updated workspace

    Sidebar->>Sidebar: invalidate workspaceKeys.lists()
    Sidebar->>Sidebar: Re-render with new logoUrl in header
Loading

Reviews (6): Last reviewed commit: "refactor: replace raw fetch with useWork..." | Re-trigger Greptile

Comment thread apps/sim/app/api/workspaces/[id]/route.ts Outdated
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

Both security findings are now addressed:

  1. Workspace auth on logo uploads — The upload route now requires workspaceId for workspace-logos context and validates admin-only access via getUserEntityPermissions. Both useWorkspaceLogoUpload and useProfilePictureUpload (used by whitelabeling) now forward workspaceId in the form data. Also added recordAudit and PostHog event tracking for logo uploads.

  2. Arbitrary logoUrl validation — The PATCH endpoint now validates logoUrl only accepts strings starting with / (local paths) or https:// (cloud storage URLs), preventing external tracker URLs.

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/blocks/blocks/cloudwatch.ts Outdated
Comment thread apps/sim/blocks/blocks/cloudwatch.ts
Comment thread apps/sim/tools/cloudformation/index.ts Outdated
waleedlatif1 and others added 7 commits April 13, 2026 14:43
- Add image/webp to ACCEPTED_IMAGE_TYPES in useProfilePictureUpload
- Add image/webp to file input accept attributes in whitelabeling settings
- Refactor useProfilePictureUpload to use refs for onUpload, onError, and
  currentImage callbacks, matching the established codebase pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These files were accidentally regressed during rebase conflict resolution,
reverting changes from #4027. Restoring to staging versions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Split the ref sync useEffect so workspaceIdRef only updates when the
workspaceId prop changes, not when onUpload/onError callbacks get new
references. Prevents setTargetWorkspaceId from being overwritten by
a re-render before the file upload completes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

The shared Workspace type requires ownerId and other fields that aren't
available from the workspaces API response mapping. Use a Pick type to
accurately represent the subset of fields actually constructed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove useState + useEffect + fetch anti-pattern for loading workspaces.
Use useWorkspacesQuery from React Query with inline filter for write/admin
permissions. Eliminates ~30 lines of manual state management, any casts,
and the Pick type workaround.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f05046a. Configure here.

@waleedlatif1 waleedlatif1 merged commit 7491d70 into staging Apr 13, 2026
12 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/workspace-logo-upload branch April 13, 2026 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant